﻿using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using NuPattern;
using NuPattern.Diagnostics;
using NuPattern.Runtime.References;
using NuPattern.VisualStudio.Solution;

namespace MVCAppToolkit.Automation.Commands
{
    /// <summary>
    /// A custom command that performs some automation.
    /// </summary>
    [DisplayName("Create Default Instances")]
    [Category("MVC Toolkit Automation")]
    [Description("Creates instances of default controllers and views for a standard ASP.NET MVC 2 Application .")]
    [CLSCompliant(false)]
    public class CreateDefaultInstances : NuPattern.Runtime.Command
    {
        private static readonly ITracer tracer = Tracer.Get<CreateDefaultInstances>();

        /// <summary>
        /// Gets or sets the solution.
        /// </summary>
        [Required]
        [Import(AllowDefault = true)]
        public ISolution Solution
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the URI reference service.
        /// </summary>
        [Required]
        [Import(AllowDefault = true)]
        public IUriReferenceService UriService
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the current element.
        /// </summary>
        [Required]
        [Import(AllowDefault = true)]
        public IControllers CurrentElement
        {
            get;
            set;
        }

        /// <summary>
        /// Executes this commmand.
        /// </summary>
        /// <remarks></remarks>
        public override void Execute()
        {
            // Verify all [Required] and [Import]ed properties have valid values.
            this.ValidateObject();

            // Make initial trace statement for this command
            tracer.Info(
                "Executing creation of default instances on current element '{0}'", this.CurrentElement.InstanceName);

            // Create Controllers
            CreateControllerInstance("Account", new[] { "Register", "Change Password", "Change Password Success", "Log Off" });
            CreateControllerInstance("Home", new[] { "About", "Index" });

            tracer.Info(
                "Executed creation of default instances on current element '{0}'", this.CurrentElement.InstanceName);
        }

        /// <summary>
        /// Creates a new named controller, with given named actions, and generic views
        /// </summary>
        private void CreateControllerInstance(string instanceName, string[] actionNames)
        {
            Guard.NotNullOrEmpty(() => instanceName, instanceName);
            Guard.NotNull(() => actionNames, actionNames);

            var controller = this.CurrentElement.CreateController(instanceName);
            if (controller != null)
            {
                // Create actions
                actionNames
                    .ToList()
                    .ForEach(an =>
                        {
                            // Create child action 
                            var action = controller.Actions.CreateAction(an);

                            // Get existing file in solution for this view.
                            var viewFile = ResolveExistingViewFile(SanitizeInstanceName(an));
                            if (viewFile != null)
                            {
                                // Create view (for existing file in solution), without unfolding new file.
                                var view = action.CreateViewForm(an, CustomFormToolkitInfo.ProductId, CustomFormToolkitInfo.ToolkitIdentifier, null, false);

                                // Add link to existing file
                                SolutionArtifactLinkReference.AddReference(view.AsProduct(), this.UriService.CreateUri(viewFile));
                            }
                        });
            }
        }

        private IItemContainer ResolveExistingViewFile(string viewname)
        {
            // Find the View file in the project
            var viewFilename = Path.ChangeExtension(viewname, "aspx");
            var parentProject = SolutionArtifactLinkReference.GetResolvedReferences(this.CurrentElement.AsCollection().View.Product, this.UriService)
                    .Where(r => r.Kind == ItemKind.Project).OfType<IProject>().FirstOrDefault();
            if (parentProject != null)
            {
                return parentProject.Traverse()
                    .Where(solutionItem => !string.IsNullOrEmpty(solutionItem.PhysicalPath)
                        && Path.GetFileName(solutionItem.PhysicalPath).Equals(viewFilename, StringComparison.OrdinalIgnoreCase))
                    .FirstOrDefault();
            }
            else
            {
                return null;
            }
        }

        private string SanitizeInstanceName(string instanceName)
        {
            return instanceName.Replace(" ", string.Empty);
        }
    }
}
